/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2012/07/12
* File: GLSLEffect.cpp
* Blog: http://www.cnblogs.com/zengqh/
**/

#include "GLSLEffect.h"

GLSLEffect::GLSLEffect()
{

}

GLSLEffect::~GLSLEffect()
{

}

bool GLSLEffect::load(const char* vs_src, const char* ps_src)
{
	if (!vs_src || !ps_src) return false;

	
	GLuint vert_shader = loadShader(GL_VERTEX_SHADER, vs_src);
	if (vert_shader == 0)
	{
		return false;
	}

	GLuint frag_shader = loadShader(GL_FRAGMENT_SHADER, ps_src);

	if (frag_shader == 0)
	{
		return false;
	}

	_effect_handle = glCreateProgram();
	if (_effect_handle == 0)
	{
		return false;
	}

	glAttachShader(_effect_handle, vert_shader);
	glAttachShader(_effect_handle, frag_shader);

	glLinkProgram(_effect_handle);

	GLint linked = 0;
	glGetProgramiv(_effect_handle, GL_LINK_STATUS, &linked);

	if (!linked)
	{
		return false;
	}

	return true;
}

/* not imp */
bool GLSLEffect::load(const char* file_name)
{
	return false;
}

void GLSLEffect::active()
{
	glUseProgram(_effect_handle);
}

void GLSLEffect::setFloat(const char* name, f32 v)
{
	GLuint handle = getVarHandle(name);
	glUniform1f(handle, v);
}

void GLSLEffect::setInt(const char* name, s32 v)
{
	GLuint handle = getVarHandle(name);
	glUniform1f(handle, v);
}

void GLSLEffect::setFloatVector(const char* name, const f32* v, s32 sz)
{
	GLuint handle = getVarHandle(name);
	switch(sz)
	{
	case 4:
		glUniform4f( handle, v[0], v[1], v[2], v[3] );
		break;
	case 3:
		glUniform3f( handle, v[0], v[1], v[2] );
		break;
	case 2:
		glUniform2f( handle, v[0], v[1] );
		break;
	case 1:
		glUniform1f( handle, v[0] );
		break;
	}
}

void GLSLEffect::setIntVector(const char* name, const s32* v, s32 sz)
{
	GLuint handle = getVarHandle(name);
	switch(sz)
	{
	case 4:
		glUniform4i( handle, v[0], v[1], v[2], v[3] );
		break;
	case 3:
		glUniform3i( handle, v[0], v[1], v[2] );
		break;
	case 2:
		glUniform2i( handle, v[0], v[1] );
		break;
	case 1:
		glUniform1i( handle, v[0] );
		break;
	}
}

void GLSLEffect::setFloatArray(const char* name, const f32* v, s32 sz)
{
	GLuint handle = getVarHandle(name);
	glUniform1fv( handle, sz, v );
}

void GLSLEffect::setIntArray(const char* name, const s32* v, s32 sz)
{
	GLuint handle = getVarHandle(name);
	glUniform1iv( handle, sz, v );
}

void GLSLEffect::setMatrix(const char* name, const f32* m)
{
	GLuint handle = getVarHandle(name);
	 glUniformMatrix4fv( handle, 1, false, m );
}

s32  GLSLEffect::getUniformHandle(const char* name)
{
	return glGetUniformLocation(_effect_handle, name);
}

s32  GLSLEffect::getAttributeHandle(const char* name)
{
	return glGetAttribLocation(_effect_handle, name);
}

GLuint GLSLEffect::loadShader(GLenum type, const char* shader_src)
{
	GLuint	shader;
	GLint	compiled;

	shader = glCreateShader(type);

	if (shader == 0)
	{
		return 0;
	}

	// Load the shader source
	glShaderSource(shader, 1, &shader_src, NULL);

	// Compile the shader
	glCompileShader(shader);

	// Check the compile status
	glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);

	if (!compiled)
	{
		return 0;
	}

	return shader;
}

GLuint GLSLEffect::getVarHandle(const char* name)
{
	return glGetUniformLocation(_effect_handle, name);
}